package compilers.AST.statement;

import compilers.AST.basics.ArrayTerm;
import compilers.AST.basics.ArrayValueList;
import compilers.AST.basics.Identifier;
import compilers.AST.expression.Expression;
import compilers.AST.types.TypeSpecifier;
import compilers.compiler.PGenerator;
import compilers.exceptions.SemanticalException;
import compilers.symbolTable.SymbolTableArrayElement;
import compilers.symbolTable.SymbolTableElement;
import compilers.symbolTable.SymbolTableScope;

public class ArrayListAssignmentStatement extends Statement {
	
	private Identifier fLValue;
	private ArrayValueList fRValue;
	
	public ArrayListAssignmentStatement() {
	}
	
	public ArrayListAssignmentStatement(int lineNr) {
		super(lineNr);
	}
		
	public void print(int identLevel) {
		println(identLevel, "ArrayListAssignmentStatement");
		fLValue.print(identLevel+1);
		fRValue.print(identLevel+1);
	}
	
	public void checkSemantics(SymbolTableScope currentScope) throws SemanticalException {
		fLValue.checkSemantics(currentScope);
		fRValue.checkSemantics(currentScope);
		
		// Check array
		SymbolTableArrayElement element = (SymbolTableArrayElement) currentScope.getElement(fLValue.getValue(), fNodeId);
		if (!(element instanceof SymbolTableArrayElement)) {
			throw new SemanticalException("'" + fLValue.getValue() + "' is not an array." , fLineNr);
		}
		
		// Check constants
		if (element.isConstant()) {
			throw new SemanticalException("Redefinition of constant array is not allowed.", getLine());
		}
				
		// Check types
		TypeSpecifier lValueType = new TypeSpecifier(fLValue.getResultType(currentScope));
		TypeSpecifier rValueType = new TypeSpecifier(fRValue.getResultType(currentScope));
		if (element.getType().getType(currentScope) == TypeSpecifier.FLOAT) {
			if ( (rValueType.getType(currentScope) != TypeSpecifier.FLOAT) && (rValueType.getType(currentScope) != TypeSpecifier.INTEGER)) {
				throw new SemanticalException("Assignment of type " + rValueType.getTypeName() + " to variable of type " + element.getType().getTypeName() + " is not allowed.", getLine());
			}
		} else {
			if (lValueType.getType(currentScope) != rValueType.getType(currentScope)) {
				throw new SemanticalException("Assignment of type '" + rValueType.getTypeName() + "' to array of type '" + lValueType.getTypeName() + "' is not allowed.", fLineNr);
			}
		}
	}
	
	public void setLValue(Identifier lValue) {
		fLValue = lValue;
	}
	
	public void setRValue(ArrayValueList rValue) {
		fRValue = rValue;
	}
	
public void generatePcode(PGenerator pGen, SymbolTableScope currentScope) {
		
		// Get array element out of symbol table
		SymbolTableArrayElement element = (SymbolTableArrayElement) currentScope.getElement(fLValue.getValue(), fNodeId);
		
		// Assign values
		fRValue.generatePcode(pGen, currentScope, element, true);	
	}
	
}
